<?php

/**
 * HOAuthAction - this the main class in hoauth extension.
 * 
 * @uses CAction
 * @version 1.2.4
 * @copyright Copyright &copy; 2013 Sviatoslav Danylenko
 * @author Sviatoslav Danylenko <dev@udf.su> 
 * @license MIT ({@link http://opensource.org/licenses/MIT})
 * @link https://github.com/SleepWalker/hoauth
 */
/**
 * HOAuthAction provides simple integration with social network authorization lib Hybridauth in Yii.
 *
 * HOAuthAction requires, that your user model implements findByEmail() method, that should return user model by its email.
 *
 * Avaible social networks: 
 *    OpenID, Google, Facebook, Twitter, Yahoo, MySpace, Windows Live, LinkedIn, Foursquare, AOL
 * Additional social networks can be found at: {@link http://hybridauth.sourceforge.net/download.html}
 *
 * Social Auth widget:
 *    <?php $this->widget('ext.hoauth.HOAuthWidget', array(
 *      'controllerId' => 'site', // id of controller where is your oauth action (default: site)
 *    )); ?>
 * uses a little modified Zocial CSS3 buttons: {@link https://github.com/samcollins/css-social-buttons/}
 */
Yii::setPathOfAlias('hoauth', dirname(__FILE__));

class HOAuthAction extends CAction {

    /**
     * @var boolean $enabled defines whether the ouath functionality is active. 
     * Useful for example for CMS,
     *  where user can enable or disable oauth functionality in control panel
     */
    public $enabled = true;

    /**
     * @var string $model yii alias for user model (or class name, when this model class exists in import path)
     */
    public $model = 'Users';

    /**
     * @var array $attributes attributes synchronization array (user model attribute => oauth attribute). 
     * List of available profile attributes you can see at {@link http://hybridauth.sourceforge.net/userguide/Profile_Data_User_Profile.html "HybridAuth's Documentation"}.
     *
     * Additional attributes:
     *    birthDate - The full date of birthday, eg. 1991-09-03
     *    genderShort - short representation of gender, eg. 'm', 'f'
     *
     * You can also set attributes, that you need to save in model too, eg.:
     *    'attributes' => array(
     *      'is_active' => 1,
     *      'date_joined' => new CDbExpression('NOW()'),
     *    ),
     *
     * @see HOAuthAction::$avaibleAtts
     */
    public $attributes;

    /**
     * @var string $scenario scenario name for the $model (optional)
     */
    public $scenario = 'insert';

    /**
     * @var string $loginAction name of a local login action
     */
    public $loginAction = 'actionLogin';

    /**
     * @var integer $duration how long the script will remember the user
     */
    public $duration = 2592000; // 30 days

    /**
     * @var boolean $useYiiUser enables support of Yii user module
     */
    public static $useYiiUser = false;

    /**
     * @var boolean $alwaysCheckPass flag to control password checking for the scenario, 
     *      when when social network returned email of existing local account. If set to
     *      `false` user will be automatically logged in without confirming account with password
     */
    public $alwaysCheckPass = true;

    /**
     * @var string $userIdentityClass UserIdentity class that will be used to log user in.
     */
    public $userIdentityClass = 'UserIdentitySocial';

    /**
     * @var string $usernameAttribute you can specify the username attribute, when user must fill it
     */
    public $usernameAttribute = false;

    /**
     * @var string $_emailAttribute
     */
    protected $_emailAttribute = false;

    /**
     * @var array $avaibleAtts Hybridauth attributes that support by this script (this a list of all available attributes in HybridAuth 2.0.11) + additional attributes (see $attributes)
     */
    protected $_avaibleAtts = array('identifier', 'profileURL', 'webSiteURL', 'photoURL', 'displayName', 'description', 'firstName', 'lastName', 'gender', 'language', 'age', 'birthDay', 'birthMonth', 'birthYear', 'email', 'emailVerified', 'phone', 'address', 'country', 'region', 'city', 'zip', 'birthDate', 'genderShort');

    public function run() {

        Yii::import('application.models.Users', true);

        $this->model = substr($this->model, strrpos($this->model, '.'));

        $this->_emailAttribute = array_search('email', $this->attributes);


        if (!isset($this->attributes) || !is_array($this->attributes) || !count($this->attributes))
            throw new CException('You must specify the model attributes for ' . __CLASS__);

        if (!in_array('email', $this->attributes))
            throw new CException("You forgot to bind 'email' field in " . __CLASS__ . "::attributes property.");

        if (isset($_GET['provider'])) {
            Yii::import('hoauth.models.*');

            $this->oAuth($_GET['provider']);
        } else {
            require('hybridauth/index.php');
            Yii::app()->end();
        }

        Yii::app()->controller->{$this->loginAction}();
    }

    /**
     * Initiates authorization with specified $provider and 
     * then authenticates the user, when all goes fine
     * 
     * @param mixed $provider provider name for HybridAuth
     * @access protected
     * @return void
     */
    protected function oAuth($provider) {

        try {
            // trying to authenticate user via social network
            $oAuth = UserOAuth::model()->authenticate($provider);

            $userProfile = $oAuth->profile;

            // If we already have a user logged in, associate the authenticated 
            // provider with the logged-in user
            if (!Yii::app()->user->isGuest) {

                $accessCode = 1;
                $oAuth->bindTo(Yii::app()->user->id);
            } else {
                $newUser = false;

                //check if bond to existing local user
                if ($oAuth->isBond) {

                    // this social network account is bond to existing local account
                    $user = call_user_func(array($this->model, 'model'))->findByPk($oAuth->user_id);
                }

                if (!$oAuth->isBond || !$user) {
                    if (!empty($userProfile->emailVerified)) {
                        // checking whether we already have a user with specified email
                        $user = call_user_func(array($this->model, 'model'))->findByEmail($userProfile->emailVerified);
                    }

                    if (FALSE == $user) {

                        // registering a new user
                        $user = new $this->model($this->scenario);
                        $newUser = true;
                    }

                    if ($this->alwaysCheckPass || $user->isNewRecord) {
                        $user = $this->processUser($user, $userProfile);
                    }
                }

                // checking if current user is not banned or anything else
                // $accessCode == 0 - user shouldn't get access
                // $accessCode == 1 - user may login
                // $accessCode == 2 - user may login, but not now (e.g. the email should be verified and activated)
                $accessCode = 1;

                if (!$oAuth->bindTo($user->primaryKey))
                    throw new Exception("Error, while binding user to provider:\n\n" . var_export($oAuth->errors, true));

                // sign user in
                if ($accessCode === 1) {

                    $identity = new UserIdentitySocial($user->email, NULL);

                    if (!Yii::app()->user->login($identity, $this->duration)) {
                        
                    }


                    if (method_exists($this->controller, 'hoauthAfterLogin'))
                        $this->controller->hoauthAfterLogin($user, $newUser);
                }

                if ($accessCode === 2)
                    Yii::app()->end(); // stopping script to let checkAccess() function render new content
            }

            if ($accessCode === 1) {
                ?>
                <script>
                    window.opener.location.reload();
                    window.close();
                </script>
                <?php

                Yii::app()->end();
            }
        } catch (Exception $e) {
            
        }
        ?>
        <script>
            window.close();
            console.log('test');
        </script>
        <?php

    }

    /**
     * Registers new user, collects username and email if needed
     *
     * @param CActiveRecord $user current user model
     * @param object $userProfile social network's user profile object
     * @access protected
     */
    protected function processUser($user, $userProfile) {

        if ($user->isNewRecord) {
            $this->populateModel($user, $userProfile);
            //create user
            $user->type = Users::TYPE_CUSTOMER;
            $user->status = Users::STATUS_ACTIVE;
            $user->date_created = time();

            $newPwd = Utils::genRandomString();

            $user->new_pass = $newPwd;

            if ($user->save()) {
                MyEmail::sendToNewUser($user, $newPwd);
                $user->completeCreateUser();
                return $user;
            }else{

            }
        }
        return $user;
        
        $form = new HUserInfoForm($user, $userProfile->emailVerified, $userProfile->identifier);

        if (!$form->validateUser()) {

            $this->controller->render('hoauth.views.form', array(
                'form' => $form,
            ));
            Yii::app()->end();
        }

        return $user;
    }

    /**
     * Populates User model with data from social network profile
     * 
     * @param CActiveRecord $user users model
     * @param mixed $profile HybridAuth user profile object
     * @access protected
     */
    protected function populateModel($user, $profile) {
//        MyEmail::send_error('User attributes. '.  json_encode($this->attributes));
        foreach ($this->attributes as $attribute => $pAtt) {
            if (in_array($pAtt, $this->_avaibleAtts)) {
                switch ($pAtt) {
                    case 'genderShort':
                        $gender = array('female' => 'f', 'male' => 'm');
                        $att = $gender[$profile->gender];
                        break;
                    //
                    case 'birthDate':
                        $att = $profile->birthYear ? sprintf("%04d-%02d-%02d", $profile->birthYear, $profile->birthMonth, $profile->birthDay) : null;
                        break;
                    case 'email':
                        $att = $profile->emailVerified;
                        break;
                    default:
                        $att = $profile->$pAtt;
                }
                if (!empty($att))
                    $user->$attribute = $att;
            }else {
                $user->$attribute = $pAtt;
            }
        }
    }

    /**
     * Checks whether the $user can be logged in
     *
     * @param CActiveRecord $user current `yii-user` user's model
     * @param boolean $render flag that enables rendering
     */
    public function yiiUserCheckAccess($user, $render = true) {
        if ($user->status == 0 && Yii::app()->getModule('user')->loginNotActiv == false) {
            $error = UserIdentitySocial::ERROR_STATUS_NOTACTIV;
            $return = 2;
        } else if ($user->status == -1) {
            $error = UserIdentitySocial::ERROR_STATUS_BAN;
            $return = 0;
        } else {
            $error = UserIdentitySocial::ERROR_NONE;
            $return = 1;
        }

        if ($error && $render) {
            $this->controller->render('hoauth.views.yiiUserError', array(
                'errorCode' => $error,
                'user' => $user,
            ));
        }

        return $return;
    }

    public function getUseYiiUser() {
        return self::$useYiiUser;
    }

    public function setUseYiiUser($value) {
        self::$useYiiUser = $value;
    }

    public static function t($message, $params = array(), $source = null, $language = null) {
        return Yii::t('HOAuthAction.root', $message, $params, $source, $language);
    }

}
